﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;

namespace Orpheus.Analyzer
{
    public class TrackParsingService
    {
        private readonly List<TrackAnalyserBase> _analyzers;

        private WaveStream fileStream;

        public TrackParsingService()
        {
            _analyzers = new List<TrackAnalyserBase>();
        }

        public TrackInfo ParseTrack(string trackFilePath)
        {
            if (!File.Exists(trackFilePath))
            {
                throw new FileNotFoundException();
            }

            TrackInfo info = new TrackInfo();
            CreateTrackAnalyzers(info);

            var stream = CreateInputStream(trackFilePath);
            
            float[] buffer = new float[stream.WaveFormat.ConvertLatencyToByteSize(1000)];

            while(fileStream.Position != fileStream.Length)
            {
                int samplesRead = stream.Read(buffer, 0, 1024);
            }

            _analyzers.ForEach(x => x.OnTrackStopped());
            //using (IWavePlayer playbackDevice = new WaveOut())
            //{
            //    var inputStream = CreateInputStream(trackFilePath);
            //    playbackDevice.Init(new SampleToWaveProvider(inputStream));

            //    playbackDevice.Play();
            //    Thread.CurrentThread.Join(100 * 60);
            //    playbackDevice.Stop();

            //    _analyzers.ForEach(x => x.OnTrackStopped());
            //}

            return info;
        }

        private void CreateTrackAnalyzers(TrackInfo info)
        {
            _analyzers.Clear();

            //_analyzers.Add(new CombFilterWithBandsTempoAnalyzer(info, GetCurrentTime));
            //_analyzers.Add(new DominantNoteAnalyser(info, GetCurrentTime));
            _analyzers.Add(new TempoAnalyzer(info, GetCurrentTime));
        }

        private TimeSpan GetCurrentTime()
        {
            return fileStream.CurrentTime;
        }

        private ISampleProvider CreateInputStream(string fileName)
        {
            fileStream = null;

            if (fileName.EndsWith(".wav"))
            {
                fileStream = OpenWavStream(fileName);
            }
            else if (fileName.EndsWith(".mp3"))
            {
                fileStream = new Mp3FileReader(fileName);
            }
            else
            {
                throw new InvalidOperationException("Unsupported extension");
            }
            var inputStream = new SampleChannel(fileStream, true);
            var sampleStream = new NotifyingSampleProvider(inputStream);

            sampleStream.Sample += OnSample;
            return sampleStream;
        }

        private void OnSample(object sender, SampleEventArgs e)
        {
            _analyzers.ForEach(x => x.ProcessSamples(e.Left, e.Right));
        }

        private static WaveStream OpenWavStream(string fileName)
        {
            WaveStream readerStream = new WaveFileReader(fileName);
            if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
            {
                readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
                readerStream = new BlockAlignReductionStream(readerStream);
            }
            return readerStream;
        }
    }
}
